﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Saxon.Api;
using System.Text.RegularExpressions;
using WMM.Tapioca.Instance;
using WMM.Tapioca.Taxonomy;
using WMM.Tapioca.Utilities;
using WMM.Tapioca.XbrlDimension;
using System.Xml;
using System.Collections;

namespace WMM.Tapioca.Formula.Filters
{
    /// <summary>
    /// The typed dimension filter can be used to match facts based upon the value for a typed dimension.
    /// </summary>
    public class TypedDimensionFilter : Filter
    {
        private string dimension;

        /// <returns> Dimension. </returns>
        public string Dimension
        {
            get { return dimension; }
            set { dimension = value; }
        }

        private string test;

        /// <returns>  XPath expression. </returns>
        public string Test
        {
            get { return test; }
            set { test = value; }
        }

       /// <summary>
        /// Constructor.
        /// </summary>
        public TypedDimensionFilter(Linkbase.Resource resource)
            : base(resource)
        {
            XElement dimensionX = resource.ResourceXElement.Descendants().Where(d => d.Parent.Name.LocalName.Equals("dimension") && 
            d.Name.LocalName.Equals("qname")).FirstOrDefault();

            if (dimensionX != null)
            {
                dimension = dimensionX.Value;
            }

            XAttribute testAttr = resource.ResourceXElement.Attribute("test");

            if (testAttr != null)
            {
                string expression = testAttr.Value.TrimEnd().TrimStart();
                expression = Regex.Replace(expression, @"\s+", " ");
                test = expression;
            }
        }


        public override List<FactItem> EvaluateFilter(VariableSet variableSet, List<FactItem> itemsToFilter, DTS dts)
        {
            this.dts = dts;

            List<FactItem> itemListTemp = new List<FactItem>();

            string thisVariableName = GetVariableName(this.Label, variableSet);

            List<string> dependecyVariables = GetDependecyVariables(variableSet, thisVariableName);

            string testResult = "false";            

            foreach (FactItem itemToFilter in itemsToFilter)
            {
                Context context = itemToFilter.ContextRef;
                List<XElement> typedMembers = context.TypedMembers;

                if (context.TypedMembers.Count == 0)
                {
                    if (Complement)
                    {
                        itemListTemp.Add(itemToFilter);
                        continue;
                    }
                }

                foreach (XElement typedMember in context.TypedMembers)
                {
                    string dimensionQName = (string)typedMember.Attribute("dimension") ?? string.Empty;

                    XElement factTyped = typedMember.Elements().FirstOrDefault();

                    if (this.Test != null)
                    {
                        testResult = EvaluateXPathExpression(dependecyVariables, variableSet, Test, typedMember);
                    }

                    if (Complement ? !(dimensionQName.Equals(Dimension) && testResult.Equals("true")) :
                                       dimensionQName.Equals(Dimension) && testResult.Equals("true"))
                    {
                        itemListTemp.Add(itemToFilter);
                        break;
                    }
                }
            }

            return itemListTemp;
        }        


        protected string EvaluateXPathExpression(List<string> dependecyVariables, VariableSet variableSet, string expression, XElement factTyped)
        {
            // Create a Processor instance.
            Processor processor = new Processor();

            // Create the XPath expression.
            XPathCompiler compiler = processor.NewXPathCompiler();

            string result = null;

            RegisterExtensionFunctions(processor);

            DeclareVariables2(dependecyVariables, variableSet, compiler);

            XPathSelector selector = compiler.Compile(expression).Load();

            SetContextItem(processor, selector, factTyped.ToXmlNode());

            foreach (string variableName in dependecyVariables)
            {
                List<FactItem> factItems = variableSet.variableItems[variableName];                

                foreach (FactItem item in factItems)
                {
                    BindVariableValue(processor, variableSet, selector, variableName, item);

                    result = selector.Evaluate().ToString();
                }
            }
            
            return result;

        }


    }
}
